﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CarbonFiberDetection.Model;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using HalconDotNet;
using ThicknessLibrary;
using System.Windows.Threading;
using HandyControl.Controls;
using MessageBox = HandyControl.Controls.MessageBox;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using System.Xml.Linq;
using System.Data;
using System.Threading;

namespace CarbonFiberDetection.ViewModel
{
    public class DetectionWindowViewModel : ViewModelBase
    {
        #region 成员
        public HWindow hWindow;
        private List<string> _CameraList;
        private int _SelectedCameraIndex;
        private ImageSource _ImageSourceT;
        private PlotModel _MyPlotModel;

        private bool _IsPretreatmentData;
        private bool _IsDownSample;
        private bool _IsDataFilte;
        private bool _IsThreshold;
        private bool _IsDetectionEdge;
        private bool _IsDisplayChar;
        private bool _IsDisplayImage;
        private bool _IsDataSmooth;

        private int _DownSampleValue;
        private int _DataFilteValue;
        private double _ThresholdValue;

        private double _CameraExposureTimeValue;
        private double _BaseLineValue;
        private double _UpperLimitValue;
        private double _LowLimitValue;

        private double _WidthDlarmValueStart;
        private double _WidthDlarmValueEnd;
        private double _HeightDlarmValueStart;
        private double _HeightDlarmValueEnd;

        private ObservableCollection<DetectedObject> _DetectedObjectList;
        private ObservableCollection<DetectedObject> _HistoryErrorList;
        #endregion

        #region 属性
        public KSJCamera CurrentCamera;
        public RelayCommand StartCommand { set; get; }
        public RelayCommand AcquisitionCommand { set; get; }
        public RelayCommand StopCommand { set; get; }
        public RelayCommand SaveConfigCommand { set; get; }
        public RelayCommand LoadConfigCommand { set; get; }
        public List<string> CameraList
        {
            set
            {
                _CameraList = value;
                RaisePropertyChanged();
            }
            get => _CameraList;
        }
        public int SelectedCameraIndex
        {
            set { _SelectedCameraIndex = value; RaisePropertyChanged(); }
            get => _SelectedCameraIndex;
        }
        public bool IsStop;
        public ImageSource ImageSourceT
        {
            set { _ImageSourceT = value;RaisePropertyChanged(); }
            get => _ImageSourceT;
        }
        public PlotModel MyPlotModel
        {
            set { _MyPlotModel = value; RaisePropertyChanged(); }
            get => _MyPlotModel;
        }

        public bool IsDisplayImage
        {
            set { _IsDisplayImage = value; RaisePropertyChanged();}
            get => _IsDisplayImage;
        }
        public bool IsDisplayChar
        {
            set { _IsDisplayChar = value; RaisePropertyChanged();}
            get => _IsDisplayChar;
        }
        public bool IsPretreatmentData
        {
            set { _IsPretreatmentData = value; RaisePropertyChanged();}
            get => _IsPretreatmentData;
        }
        public bool IsDownSample
        {
            set { _IsDownSample = value; RaisePropertyChanged(); }
            get => _IsDownSample;
        }
        public bool IsDataFilte
        {
            set { _IsDataFilte = value; RaisePropertyChanged(); }
            get => _IsDataFilte;
        }
        public bool IsThreshold
        {
            set { _IsThreshold = value; RaisePropertyChanged();}
            get => _IsThreshold;
        }
        public bool IsDetectionEdge
        {
            set { _IsDetectionEdge = value; RaisePropertyChanged(); }
            get => _IsDetectionEdge;
        }
        public bool IsDataSmooth
        {
            set { _IsDataSmooth = value;RaisePropertyChanged(); }
            get => _IsDataSmooth;
        }
        public int DownSampleValue
        {
            set { _DownSampleValue = value; RaisePropertyChanged();}
            get => _DownSampleValue;
        }
        public int DataFilteValue
        {
            set { _DataFilteValue = value;RaisePropertyChanged(); }
            get => _DataFilteValue;
        }
        public double ThresholdValue
        {
            set { _ThresholdValue = value; RaisePropertyChanged(); }
            get => _ThresholdValue;
        }
        public double CameraExposureTimeValue
        {
            set 
            { 
                _CameraExposureTimeValue = value;
                if (CurrentCamera != null && CurrentCamera.IsConnect)
                    CurrentCamera.SetExposureTime((float)value);
                RaisePropertyChanged(); 
            }
            get => _CameraExposureTimeValue;
        }
        public double BaseLineValue
        {
            set { _BaseLineValue = value; RaisePropertyChanged();}
            get => _BaseLineValue;
        }
        public double UpperLimitValue
        {
            set { _UpperLimitValue = value;RaisePropertyChanged(); }
            get => _UpperLimitValue;
        }
        public double LowLimitValue
        {
            set { _LowLimitValue = value;RaisePropertyChanged(); }
            get => _LowLimitValue;
        }

        public double WidthDlarmValueStart
        {
            set 
            { 
                _WidthDlarmValueStart = value;
                DataOperator.WidthDlarmValueStart = value;
                RaisePropertyChanged(); 
            }
            get => _WidthDlarmValueStart;
        }
        public double WidthDlarmValueEnd
        {
            set 
            { 
                _WidthDlarmValueEnd = value; 
                DataOperator.WidthDlarmValueEnd= value;
                RaisePropertyChanged(); 
            }
            get => _WidthDlarmValueEnd;
        }
        public double HeightDlarmValueStart
        {
            set 
            { 
                _HeightDlarmValueStart = value;
                DataOperator.HeightDlarmValueStart= value;
                RaisePropertyChanged(); 
            }
            get => _HeightDlarmValueStart;
        }
        public double HeightDlarmValueEnd
        {
            set 
            { 
                _HeightDlarmValueEnd = value;
                DataOperator.HeightDlarmValueEnd = value;
                RaisePropertyChanged(); 
            }
            get => _HeightDlarmValueEnd;
        }

        public ObservableCollection<DetectedObject> DetectedObjectList
        {
            set 
            { 
                _DetectedObjectList = value;
                RaisePropertyChanged(); 
            }
            get => _DetectedObjectList;
        }
        public ObservableCollection<DetectedObject> HistoryErrorList
        {
            set
            {
                _HistoryErrorList = value;
                RaisePropertyChanged();
            }
            get => _HistoryErrorList;
        }
        public bool EnableAcquisition { set; get; } = false;
        #endregion

        #region 函数
        public DetectionWindowViewModel()
        {
            SystemInit();
            StartCommand = new RelayCommand(() =>
            {
                var selectCameraName = CameraList[SelectedCameraIndex];
                CurrentCamera = new KSJCamera();
                CurrentCamera.ConfigFile = Path.Combine(Environment.CurrentDirectory, $"{selectCameraName}.ini");
                CurrentCamera.ConnectCamera(selectCameraName);
                CurrentCamera.SetCaptureType(CAPTURE_TYPE.PROFILE);
                CurrentCamera.LiveImageCallback = MyLiveImageCallBack;

                var result = MessageBox.Show($"连接成功");
            });
            AcquisitionCommand = new RelayCommand(() =>
            {
                IsStop = true;
                EnableAcquisition = true;
                Task.Run(async() =>
                {
                    while (EnableAcquisition)
                    {
                        CurrentCamera.CaptureImage();
                        MyLiveImageCallBack(1);
                        await Task.Delay(100);
                    }
                });
            });
            StopCommand = new RelayCommand(() =>
            {
                IsStop = false;
                EnableAcquisition = false;
                Thread.Sleep(300);
                CurrentCamera.StopCaptureImage();
            });
            SaveConfigCommand = new RelayCommand(() =>
            {
                var fileName = Path.Combine(Path.Combine(Environment.CurrentDirectory, "SoftwareConfig"), $"Camera{SelectedCameraIndex}.xml");
                SaveConfig(fileName);
                MessageBox.Show("保存配置成功", caption:"提示", MessageBoxButton.OK, MessageBoxImage.Information);
            });
            LoadConfigCommand = new RelayCommand(() =>
            {
                var fileName = Path.Combine(Path.Combine(Environment.CurrentDirectory, "SoftwareConfig"), $"Camera{SelectedCameraIndex}.xml");
                ReadConfig(fileName);
                MessageBox.Show("导入配置成功", caption: "提示", MessageBoxButton.OK, MessageBoxImage.Information);
            });
        }
        /// <summary>
        /// 系统初始化
        /// </summary>
        public void SystemInit()
        {
            CameraList = KSJCamera.GetDeviceList();
            SelectedCameraIndex = 0;

            MyPlotModel = new PlotModel()
            {
                Title = "test",
                Subtitle = "数据"
            };
            var lineSeries1 = new LineSeries
            {
                Title = "Series 2",
                MarkerType = MarkerType.Square
            };
            //lineSeries1.InterpolationAlgorithm = InterpolationAlgorithms.CanonicalSpline; //定义为曲线
            MyPlotModel.Series.Add(lineSeries1);

            IsPretreatmentData = true;
            IsDataSmooth = true;
            IsDownSample = true;
            IsDataFilte = true;
            IsThreshold = true;
            IsDetectionEdge = true;

            DataFilteValue = 5;
            DownSampleValue = 4;
            ThresholdValue = 20.5;
            IsDisplayImage = false;
            IsDisplayChar = true;
            BaseLineValue = 68.000;
            UpperLimitValue = 69.000;
            LowLimitValue = 68.000;

            WidthDlarmValueStart = 5.0;
            WidthDlarmValueEnd = 12.0;
            HeightDlarmValueStart = 0.05;
            HeightDlarmValueEnd = 0.25;

            DetectedObjectList = new ObservableCollection<DetectedObject>();
            HistoryErrorList = new ObservableCollection<DetectedObject>();
        }
        public void MyLiveImageCallBack(int i)
        {
            try
            {
                if (IsDisplayImage)
                {
                    var image = HalconWindowEx.BitmapToHObjectColor(CurrentCamera.PreviewBitmap);
                    this.hWindow?.DispObj(image);
                    image?.Dispose();
                }
                var X_ProfileData = CurrentCamera.X_ProfileData;
                var Z_ProfileData = CurrentCamera.Z_ProfileData;

                List<double> temp = null;
                if (X_ProfileData != null && Z_ProfileData != null &&
                    X_ProfileData.Count() > 0 && Z_ProfileData.Count() > 0)
                {
                    if (IsPretreatmentData)
                        temp = DataOperator.PretreatmentData(X_ProfileData, Z_ProfileData, BaseLineValue);
                    if (IsDownSample)
                        temp = DataOperator.DownSample(temp, DownSampleValue);
                    //if (IsDataFilte)
                    //    temp = DataOperator.DataFilte(temp, DataFilteValue);
                    if (IsDataSmooth)
                        temp = DataOperator.DataSmooth(temp, DataFilteValue,1000);
                    if (IsThreshold)
                        temp = DataOperator.Threshold(temp, ThresholdValue, 999);
                    if (IsDetectionEdge)
                    {
                        List<double> tempX = new List<double>();
                        for (int r = 0; r < X_ProfileData.Count(); r++)
                            tempX.Add((double)X_ProfileData[r]);

                        List<double> tempZ = new List<double>();
                        for (int r = 0; r < Z_ProfileData.Count(); r++)
                            tempZ.Add((double)Z_ProfileData[r]);
                        
                        var dataList = DataOperator.DetectionEdge(tempX, tempZ, temp, DownSampleValue, BaseLineValue);
                        try
                        {
                            if (Application.Current != null && dataList != null && dataList.Count > 0)
                            {
                                Application.Current.Dispatcher.Invoke(() =>
                                {
                                    foreach (var det in DetectedObjectList)
                                        det.Dispose();

                                    DetectedObjectList.Clear();
                                    int count = 0;
                                    foreach (var data in dataList)
                                    {
                                        DetectedObjectList.Add(new DetectedObject()
                                        {
                                            Index = count,
                                            LeftEdge = data.leftEdge,
                                            RightEdge = data.rightEdge,
                                            Width = data.width,
                                            Height = data.Height
                                        });
                                        count++;
                                    }
                                    GC.Collect();

                                    //检测 添加历史记录
                                    UInt64 index = (ulong)HistoryErrorList.Count;
                                    if(HistoryErrorList.Count > 100)
                                        HistoryErrorList.Clear();
                                    foreach (var detected in DetectedObjectList)
                                    {
                                        if((detected.Width != null && (detected.Width < WidthDlarmValueStart || detected.Width > WidthDlarmValueEnd)) ||
                                            (detected.Height != null && (detected.Height < HeightDlarmValueStart || detected.Height > HeightDlarmValueEnd)))
                                        {
                                            HistoryErrorList.Add(new DetectedObject()
                                            {
                                                Index = (int?)index,
                                                Width = Math.Round((double)detected.Width,3),
                                                Height = detected.Height,
                                                LeftEdge = detected.LeftEdge, 
                                                RightEdge = detected.RightEdge,
                                                DetectedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                                            });
                                            index++;
                                        }
                                    }
                                });
                            }
                        }
                        catch (Exception ex)
                        {

                        }
                    }
                }


                if(IsDisplayChar)
                    DisplayChar(null, temp);
            }
            catch (HalconException hex)
            {

            }
        }

        /// <summary>
        /// 显示图表
        /// </summary>
        /// <param name="xList"></param>
        /// <param name="ylist"></param>
        public void DisplayChar(List<double> xList, List<double> ylist)
        {
            try
            {
                if (ylist == null || ylist.Count == 0)
                    return;
                if (MyPlotModel.Series[0] is LineSeries lineSeries)
                {
                    lineSeries.Points.Clear();
                    for (int i = 0; i < ylist.Count; i++)
                        lineSeries.Points.Add(new DataPoint(i, ylist[i]));
                }
                MyPlotModel.InvalidatePlot(true);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="Name"></param>
        public void SaveConfig(string Name)
        {
            var fileName = Name;
            if (File.Exists(fileName))
            {

            }
            XElement root = new XElement("Root");

            root.Add(new XElement("IsDisplayImage", IsDisplayImage.ToString()));
            root.Add(new XElement("IsDisplayChar", IsDisplayChar.ToString()));
            root.Add(new XElement("IsPretreatmentData", IsPretreatmentData.ToString()));
            root.Add(new XElement("IsDownSample", IsDownSample.ToString()));
            root.Add(new XElement("DownSampleValue", DownSampleValue.ToString()));
            root.Add(new XElement("IsDataSmooth", IsDataSmooth.ToString()));
            root.Add(new XElement("DataFilteValue", DataFilteValue.ToString()));
            root.Add(new XElement("IsThreshold", IsThreshold.ToString()));
            root.Add(new XElement("ThresholdValue", ThresholdValue.ToString()));
            root.Add(new XElement("IsDetectionEdge", IsDetectionEdge.ToString()));
            root.Add(new XElement("BaseLineValue", BaseLineValue.ToString()));
            root.Add(new XElement("UpperLimitValue", UpperLimitValue.ToString()));
            root.Add(new XElement("LowLimitValue", LowLimitValue.ToString()));
            root.Add(new XElement("CameraExposureTimeValue", CameraExposureTimeValue.ToString()));
            root.Add(new XElement("WidthDlarmValueStart", WidthDlarmValueStart.ToString()));
            root.Add(new XElement("WidthDlarmValueEnd", WidthDlarmValueEnd.ToString()));
            root.Add(new XElement("HeightDlarmValueStart", HeightDlarmValueStart.ToString()));
            root.Add(new XElement("HeightDlarmValueEnd", HeightDlarmValueEnd.ToString()));
            root.Save(fileName);
        }
        /// <summary>
        /// 读取配置
        /// </summary>
        /// <param name="Name"></param>
        public void ReadConfig(string Name)
        {
            var root = XElement.Load(Name);
            if (bool.TryParse(root.Element("IsDisplayImage").Value, out bool IsDisplayImage))
                this.IsDisplayImage = IsDisplayImage;
            if (bool.TryParse(root.Element("IsDisplayChar").Value, out bool IsDisplayChar))
                this.IsDisplayChar = IsDisplayChar;
            if (bool.TryParse(root.Element("IsPretreatmentData").Value, out bool IsPretreatmentData))
                this.IsPretreatmentData = IsPretreatmentData;
            if (bool.TryParse(root.Element("IsDownSample").Value, out bool IsDownSample))
                this.IsDownSample = IsDownSample;
            if (int.TryParse(root.Element("DownSampleValue").Value, out int DownSampleValue))
                this.DownSampleValue = DownSampleValue;
            if (bool.TryParse(root.Element("IsDataSmooth").Value, out bool IsDataSmooth))
                this.IsDataSmooth = IsDataSmooth;
            if (int.TryParse(root.Element("DataFilteValue").Value, out int DataFilteValue))
                this.DataFilteValue = DataFilteValue;
            if (bool.TryParse(root.Element("IsThreshold").Value, out bool IsThreshold))
                this.IsThreshold = IsThreshold;
            if (double.TryParse(root.Element("ThresholdValue").Value, out double ThresholdValue))
                this.ThresholdValue = ThresholdValue;
            if (bool.TryParse(root.Element("IsDetectionEdge").Value, out bool IsDetectionEdge))
                this.IsDetectionEdge = IsDetectionEdge;
            if (double.TryParse(root.Element("BaseLineValue").Value, out double BaseLineValue))
                this.BaseLineValue = BaseLineValue;
            if (double.TryParse(root.Element("UpperLimitValue").Value, out double UpperLimitValue))
                this.UpperLimitValue = UpperLimitValue;
            if (double.TryParse(root.Element("LowLimitValue").Value, out double LowLimitValue))
                this.LowLimitValue = LowLimitValue;
            if (double.TryParse(root.Element("CameraExposureTimeValue").Value, out double CameraExposureTimeValue))
                this.CameraExposureTimeValue = CameraExposureTimeValue;
            if (double.TryParse(root.Element("WidthDlarmValueStart").Value, out double WidthDlarmValueStart))
                this.WidthDlarmValueStart = WidthDlarmValueStart;
            if (double.TryParse(root.Element("WidthDlarmValueEnd").Value, out double WidthDlarmValueEnd))
                this.WidthDlarmValueEnd = WidthDlarmValueEnd;
            if (double.TryParse(root.Element("HeightDlarmValueStart").Value, out double HeightDlarmValueStart))
                this.HeightDlarmValueStart = HeightDlarmValueStart;
            if (double.TryParse(root.Element("HeightDlarmValueEnd").Value, out double HeightDlarmValueEnd))
                this.HeightDlarmValueEnd = HeightDlarmValueEnd;
        }
        #endregion
    }
}
